#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <string.h>
#include <netinet/in.h>

#include <sstream>

#include "SockTCP.h"

char* str_echo (int sockfd);
bool str_send(int sockfd, std::string msg);

SockTCP::SockTCP(Robot *r):Traductor(r){
	
}

SockTCP::~SockTCP(){
	
}

void SockTCP::Run(){
	int sockfd, newsockfd;
	socklen_t clilen;
	struct sockaddr_in serv_addr, cli_addr;
	fd_set rset, allset;
	
	int maxfdp1, nbfd, i, sockcli;
		
	
	//create socket (listen)
	
	if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) <0){
		std::cout << "error while creating socket" << std::endl;
		exit(1);
	}
	
	bzero((void*)(& serv_addr), sizeof(serv_addr));
	serv_addr.sin_family 		= AF_INET;
	serv_addr.sin_addr.s_addr 	= htonl(INADDR_ANY);
	serv_addr.sin_port 			= htons(PORT_TCP);
	
	if(bind(sockfd,(struct sockaddr *)&serv_addr, sizeof(serv_addr) ) <0){
		std::cout << "error while binding" << std::endl;
		exit(2);
	}
	
	if (listen(sockfd, SOMAXCONN) <0) {
		std::cout << "error while listening" << std::endl;
		exit (1);
	}
	
	// Initialisation
	maxfdp1 = sockfd + 1;
	
		
	FD_ZERO(&rset);
	FD_ZERO(&allset);
	FD_SET(sockfd,&rset);
	
	while(1){
		allset 	= rset;
		nbfd 	= select(maxfdp1,&allset,0,0,0);
		
		if(FD_ISSET(sockfd,&allset)){//new client
			clilen		= sizeof(cli_addr);
			newsockfd 	= accept(sockfd,(struct sockaddr*)&cli_addr,  &clilen);
			
			if (newsockfd < 0){
				std::cout << "error accept" << std::endl;
				exit (1);
			}
			
			
			//Add new client
			mClients.push_back(newsockfd);
			
			//add new client in the rset
			FD_SET(newsockfd,&rset);
			
			//position maxfdp1
			if(newsockfd >= maxfdp1)
				maxfdp1 = newsockfd + 1;
			nbfd--;
		}
		
		i=0;
		int j = mClients.size();
		while(nbfd>0 && i < FD_SETSIZE){
			//get the i-element
			std::list<int>::const_iterator it(mClients.begin());
			int k;
			for(k=0;k<i;k++)
				it++;
			int at = *(it); 
			if(at >= 0 && FD_ISSET(at,&allset)){
				char * msg = str_echo(at);
				switch(msg[0]){
				case 'k' :
					{
					this->mRobot->Kill_Robot();
					close(sockfd);
					}
				case 'd' :
					{
					close(at);
					FD_CLR(at,&rset);
					mClients.remove(i);
					}
					break;
				case 'p' :
					{
					std::string mess;
					std::stringstream strm(std::stringstream::in | std::stringstream::out);
					strm << this->mRobot->Get_Position('x') << ":" << this->mRobot->Get_Position('y') << ":" << this->mRobot->Get_Position('a') << std::endl;
					strm >> mess;
					str_send(at, mess);
					}
					break;
				default:
					int code;
					long value;
					
					std::stringstream stream(std::stringstream::in | std::stringstream::out);
					std::string str(msg);
					free(msg); 
					stream << str;
					stream >> code >> value;
					std::cout << code << " : " << value << std::endl;
					if(value != 0)
						this->perform(code, value);
					value = 0;
				}
				nbfd--;
			}
			i++;
		}
	}
}

void SockTCP::launch(){
	this->StartRunThreaded();
}

bool str_send(int sockfd, std::string msg)
{
	if ( write(sockfd, msg.c_str(), msg.length()*sizeof(char)) < 0 )  {
		perror ("servmulti : : writen error on socket");
		exit (1);
	}
}

char* str_echo (int sockfd){
    int nrcv;
	char *msg = (char*)malloc(BUFSIZE*sizeof(char));

	/*    * Attendre  le message envoye par le client 
	*/
	//memset((char*) msg, 0, sizeof(msg) );
	if ( (nrcv= read ( sockfd, msg, (BUFSIZE-1)*sizeof(char)) ) < 0 )  {
		perror ("servmulti : : readn error on socket");
		exit (1);
	}
	msg[nrcv-1]='\0';
	return msg;
}
